/**
 * @widoc $.fn.initDragLoader
 * @namespace comp
 * @des 初始化 dragloader，将在 el 中添加 wi-drag-before, wi-drag-after，el中应只有一个高度为 100% 的非定位元素。
 <p class="t_red">注意：el 不能通过 box-flex 控制高度，将引起拖拽效果的异常。</p>
 * @depends eventHelper/$.eventHelper, styleHelper/$.styleHelper
 * @type function
 * @param {object} opts
 * @param {number=} opts.threshold helper中内容高度，默认为 40
 * @param {number=} opts.dragDownThreshold 向下拖拽时helper中内容高度，默认为 opts.threshold
 * @param {number=} opts.dragUpThreshold 同上
 * @param {boolean=} opts.disableDragDown 是否禁止向下拖拽，默认为 false
 * @param {boolean=} opts.disableDragUp 同上
 * @param {function=} opts.beforeDrag 拖拽生效前的回调函数，若返回 true，则阻止拖拽
 * @param {function=} opts.dragDownHelper 向下滑动时helper中dom字符串，参数：status（'default','prepare','load'）
 * @param {function=} opts.dragUpHelper 同上
 * @param {function=} opts.onDragDownStatus 向下滑动时切换状态时的回调，参数：dragger（组件返回对象）,status（切换到的新状态-'default','prepare','load'）
 * @param {function=} opts.onDragUpStatus 同上
 * @return {object} obj
 * @rtn {function} obj.reset() 还原状态
 * @rtn {function} obj.setDragDownDisabled(disabled) 设置 opts.disableDragDown
 * @rtn {function} obj.setDragUpDisabled(disabled) 同上
 * @rtn {function} obj.destroy() 销毁
 */
$.fn.initDragLoader = function(opts){
    var el = $(this);
    opts = $.extend({
        threshold: 40,// hold 高度
        //dragDownThreshold:threshold,
        //dragUpThreshold:threshold,
        disableDragDown: false,
        disableDragUp: false,
        beforeDrag: $.noop,
        //dragDownHelper: function,// 返回向下滑动时helper中dom字符串，参数：status（'default','prepare','load'）
        //dragUpHelper: function,
        onDragDownStatus: $.noop,// 向下滑动时切换状态时的回调，参数：dragger,status（切换到的新状态-'default','prepare','load'）
        onDragUpStatus: $.noop
    }, opts);
    /* 辅助功能 */
    var msPointerEnabled = $.eventHelper.msPointerEnabled,
        _transName = $.styleHelper.translateName('transition'),
        transEndEvent = $.eventHelper.transformEndEvent,
        fGetEventAttr = $.eventHelper.fGetEventAttr;
    var listenTransition = function(target, duration, callbackFn){
        var clear = function(){
                if(target.transitionTimer) clearTimeout(target.transitionTimer);
                target.transitionTimer = null;
                target.removeEventListener(transEndEvent, handler, false);
            },
            handler = function(){
                clear();
                callbackFn && callbackFn();
            };
        clear();
        target.addEventListener(transEndEvent, handler, false);
        target.transitionTimer = setTimeout(handler, duration + 100);
    };
    /* 属性初始化 */
    if(!opts.dragDownThreshold){
        opts.dragDownThreshold = opts.threshold;
    }
    if(!opts.dragUpThreshold){
        opts.dragUpThreshold = opts.threshold;
    }
    if(!opts.dragDownHelper){
        opts.dragDownHelper = function(status){
            if(status == 'default'){
                return '下拉加载最新';
            }
            else if(status == 'prepare'){
                return '释放刷新';
            }
            else if(status == 'load'){
                return '加载中...';
            }
        }
    }
    if(!opts.dragUpHelper){
        opts.dragUpHelper = function(status){
            if(status == 'default'){
                return '向上拉加载更多';
            }
            else if(status == 'prepare'){
                return '释放刷新';
            }
            else if(status == 'load'){
                return '加载中...';
            }
        }
    }

    var header, footer, cont;
    var canDragDown, canDragUp;// start 时计算当前是否允许拖拽
    var _draggable = true;
    var _coords = null;
    var init = function(){
        if(($.styleHelper.getValue(el, 'position') || 'static' ) === 'static'){
            el.css('position', 'relative');
        }
        cont = el.children().eq(0);
        el.addClass('wi-drag');
        cont.addClass('wi-drag-sub');
        header = $('<div class="wi-drag-before">' +
            '<div class="wi-drag-status"><div class="wi-drag-ico"></div><span class="wi-drag-txt"></span></div>' +
            '</div>');
        footer = $('<div class="wi-drag-after">' +
            '<div class="wi-drag-status"><div class="wi-drag-ico"></div><span class="wi-drag-txt"></span></div>' +
            '</div>');
        el.prepend(header);
        el.append(footer);
        el.on($.eventHelper.touchstartEvent, _onTouchStart);
    };

    var _onTouchStart = function(e){
        if(!_draggable) return;// 已经在拖拽的过程中
        var startScrollY = cont.scrollTop();// 内容部分 scrollTop
        canDragDown = opts.disableDragDown !== true && startScrollY <= 0;// 是否允许向下拖拽
        canDragUp = opts.disableDragUp !== true && startScrollY + cont.height() >= cont[0].scrollHeight;// 是否允许向上拖拽
        if((canDragDown || canDragUp) && opts.beforeDrag() !== false){// 允许拖拽，且未被拦截
            _draggable = false;
            var doc = $(document);
            doc.off($.eventHelper.touchmoveEvent);
            doc.off($.eventHelper.touchendEvent);
            doc.on($.eventHelper.touchmoveEvent, _onTouchMove);
            doc.on($.eventHelper.touchendEvent, _onTouchEnd);
            _coords = {};
            if(msPointerEnabled){
                _coords.startX = e.screenX;
                _coords.startY = e.screenY;
                _coords.identifier = e.pointerId;// 记录触摸对象
            }
            else{
                var touch = fGetEventAttr(e, 'targetTouches')[0];
                _coords.startX = touch.screenX;
                _coords.startY = touch.screenY;
                _coords.identifier = touch.identifier;// 记录触摸对象
            }
            _coords.startScrollY = startScrollY;
        }
    };
    var _findTouch = function(touches){
        if(!_coords) return;
        for(var i = 0; i < touches.length; i++){
            if(touches[i].identifier === _coords.identifier){// 触发 start 的 touch 对象未释放
                return touches[i];
            }
        }
    };
    var _onTouchMove = function(e){
        var stopX, stopY, clientX, clientY;
        if(_coords.baseline === 'hor'){// 横向滑动
            _onTouchEnd();
            return;
        }
        // 判断是否为 start 的触摸点移动
        if(msPointerEnabled){
            if(e.pointerId == _coords.identifier){
                stopX = e.screenX;
                stopY = e.screenY;
                clientX = e.clientX;
                clientY = e.clientY;
            }
            else return;
        }
        else{
            var touch = _findTouch(fGetEventAttr(e, 'changedTouches'));
            if(touch){
                stopX = touch.screenX;
                stopY = touch.screenY;
                clientX = touch.clientX;
                clientY = touch.clientY;
            }
            else return;
        }
        var startY = _coords.startY,
            offsetY = stopY - startY;
        var winW = window.innerWidth,
            winH = window.innerHeight;
        var aTouchDir, sFirstDir;
        if(!_coords.baseline){// 还没有发生移动，记录第一次移动的方向
            aTouchDir = $.eventHelper.fGetMoveDirection(_coords.startX, _coords.startY, stopX, stopY);
            sFirstDir = aTouchDir[0];
            if(aTouchDir[2] || sFirstDir === 'l' || sFirstDir === 'r'){
                _coords.baseline = 'hor';
                _onTouchEnd();
                return;
            }
            _coords.baseline = 'ver';
        }
        if(canDragDown && offsetY > 0){// 向下滑动
            //e.preventDefault();
            _coords.orient = 'down';
            _hideHelper(footer);
            header.addClass('active');
            header.css('height', offsetY + 'px');
            _processStatus(offsetY, true);
        }
        else if(canDragUp && offsetY < 0){
            //e.preventDefault();
            _coords.orient = 'up';
            _hideHelper(header);
            footer.addClass('active');
            offsetY = -offsetY;
            footer.css('height', offsetY + 'px');
            el.scrollTop(offsetY);
            _processStatus(offsetY, true);
        }
        if($.browser.versions.ios){// ios 中通过move时进入边界触发end事件，防止移出屏幕时无反应
            var borderSize = Math.min(winW, winH) / 10;
            if(clientX < borderSize || clientY < borderSize || clientX > winW - borderSize || clientY > winH - borderSize){
                _onTouchEnd();
            }
        }
    };
    var _onTouchEnd = function(e){
        if(_draggable == false){
            // 由 touchend 事件触发 - 之所以需要判断是因为 touchmove 中可能因手指靠近边界调用 _onTouchEnd 结束 drag
            if(!e || !fGetEventAttr(e, 'changedTouches') || !!_findTouch(fGetEventAttr(e, 'changedTouches'))){
                //var doc=$(document);
                //doc.off($.eventHelper.touchmoveEvent);
                //doc.off($.eventHelper.touchendEvent);
                _translate();
            }
        }
    };
    /**
     * @param offsetY {number} helper 容器高度
     * @param moving {boolean} 是否正在移动
     * @return {*}
     * @private
     */
    var _processStatus = function(offsetY, moving){
        if(!_coords) return;
        var orient = _coords.orient// down|up
            , status = _coords.status;// undefined,'default','prepare','load'
        if(orient){
            var upperStr = orient.charAt(0).toUpperCase() + orient.substr(1)// 首字母转大写
                , overflow = offsetY > opts['drag' + upperStr + 'Threshold'];// helper尺寸是否已经超过内容尺寸
            if(!overflow && status != 'default'){
                status = 'default';
            }
            else if(moving && overflow && status != 'prepare'){
                status = 'prepare';
            }
            else if(!moving && overflow && status != 'load'){
                status = 'load';
            }
            if(status != _coords.status){
                _coords.status = status;
                var helper = opts['drag' + upperStr + 'Helper'];
                if(helper){
                    if(orient == 'down'){
                        header.find('.wi-drag-txt').html(helper(status));
                        header.find('.wi-drag-status').attr('data-drag', status);
                    }
                    else{
                        footer.find('.wi-drag-txt').html(helper(status));
                        footer.find('.wi-drag-status').attr('data-drag', status);
                    }
                }
                opts['onDrag' + upperStr + 'Status'](status, returnObj);
            }
        }
        return status;
    };

    var _hideHelper = function(helper){
        helper.removeClass('active');
        helper.css('height', 0);
    };

    var _translate = function(){
        if(!_coords) return;
        var orient = _coords.orient
            , offsetY;
        var endFn = function(){// 隐藏 helper 并重置 _coords、_draggable
            if(!_coords) return;
            _processStatus(offsetY, false);
            if(!orient || _coords.status !== 'load'){
                _hideHelper(header);
                _hideHelper(footer);
                _coords = null;
                _draggable = true;
            }
            else if(orient == 'down'){
                _hideHelper(footer);
            }
            else if(orient == 'up'){
                _hideHelper(header);
            }
            // 解绑事件
            var doc = $(document);
            doc.off($.eventHelper.touchmoveEvent);
            doc.off($.eventHelper.touchendEvent);
        };
        if(orient){
            var maxDuration = 200
                , helperEl = orient == 'down' ? header : footer
                , upperStr = orient.charAt(0).toUpperCase() + orient.substr(1)
                , threshold = opts['drag' + upperStr + 'Threshold'];// helper 内容高度
            offsetY = helperEl.height();// helper 高度
            var adjustHeight = offsetY > threshold ? threshold : 0
                , duration = Math.ceil((offsetY - adjustHeight) / threshold * maxDuration);
            duration = duration > maxDuration ? maxDuration : duration;// 拉回 helper 的动画时间
            listenTransition(helperEl[0], duration, endFn);
            helperEl.css(_transName, 'height ' + duration + 'ms');
            setTimeout(function(){
                helperEl[0].style.height = adjustHeight + 'px';
                helperEl.css(_transName, '');
            }, 0);
        }
        else{
            endFn();
        }
    };
    var _destroy = function(){
        header.remove();
        footer.remove();
        el.off($.eventHelper.touchstartEvent);
        var doc = $(document);
        doc.off($.eventHelper.touchmoveEvent);
        doc.off($.eventHelper.touchendEvent);
    };
    var returnObj = {
        reset: _translate,
        isLoading: function(){
            return _coords && _coords.status == 'load';
        },
        setDragDownDisabled: function(disabled){
            opts.disableDragDown = disabled;
        },
        setDragUpDisabled: function(disabled){
            opts.disableDragUp = disabled;
        },
        destroy: _destroy
    };
    init();
    return returnObj;
};